/*
 * MongoDB.cpp
 *
 *  Created on: 2013. 12. 3.
 *      Author: jjaehuny
 */

#include "MongoDB.h"
#include "Bson.h"
#include "Static.h"

namespace ProjectZ { namespace NGameLog {

MongoDB::Wrapper::Wrapper(std::string ip, int port)
{
	int status = mongo_client( &_conn, ip.c_str(), port );
	if( status != MONGO_OK )
	{
		switch ( _conn.err )
		{
			case MONGO_CONN_NO_SOCKET:  printf( "no socket\n" ); return;
			case MONGO_CONN_FAIL:       printf( "connection failed\n" ); return;
			case MONGO_CONN_NOT_MASTER: printf( "not master\n" ); return;
			default : return;
		}
	}
}

MongoDB::Wrapper::~Wrapper()
{
	mongo_destroy( &_conn );
}

void
MongoDB::Wrapper::Execute(Bson * pBson)
{
	bson * pbson = pBson->GetBsonData();
	if( NULL == pbson )
		return;

	if (MONGO_OK != mongo_check_connection( &_conn ))
	{
		mongo_reconnect( &_conn );
	}
	if( mongo_insert( &_conn, pBson->GetCollections().c_str(), pbson, 0 ) == MONGO_ERROR && _conn.err == MONGO_IO_ERROR )
		mongo_reconnect( &_conn );
}

MongoDB::MongoDB(int connectCount) : _threadPool(1)
{
	_connectCount = connectCount;
}

MongoDB::~MongoDB()
{
	std::for_each(_clsWrapperPool.begin(), _clsWrapperPool.end(), [&](std::vector<Wrapper*>::value_type & pair){
		delete pair;
	});
}

void
MongoDB::Init(std::string ip , int port)
{
	for(int i=0; i<_connectCount; i++)
	{
		Wrapper * pWrapper = new Wrapper(ip, port);
		_clsWrapperPool.push_back(pWrapper);
	}
}

void
MongoDB::Push(Bson * pBson)
{
	bson_finish( pBson->GetBsonData() );

	{
		std::lock_guard<std::mutex> lock(_mutex);
		_clsBsonVector.push_back(pBson);
	}
	_threadPool.PostTask(std::bind(&MongoDB::work, this));
}

void
MongoDB::work()
{
	Bson * pBson;
	while(true)
	{
		{
			std::lock_guard<std::mutex> lock(_mutex);
			if(_clsBsonVector.size() <= 0)
				break;

			pBson = _clsBsonVector.front();
			_clsBsonVector.pop_front();

			Wrapper * pWrapper = _clsWrapperPool.front();
			if(NULL == pWrapper)
				break;
			else
				_clsWrapperPool.pop_back();

			pWrapper->Execute(pBson);

			_clsWrapperPool.push_back(pWrapper);

			NGameLog::Static::Instance().DEL(pBson);
		}
	}
}


} /*NGameLog*/ } /*ProjectZ*/
